package com.nercel.dsj.gksales.shiro.service.impl;

import com.nercel.dsj.gksales.dao.mapper.UserMapper;
import com.nercel.dsj.gksales.model.QueryParams;
import com.nercel.dsj.gksales.model.entity.Permission;
import com.nercel.dsj.gksales.model.entity.User;
import com.nercel.dsj.gksales.service.PermissionService;
import com.nercel.dsj.gksales.shiro.RestPathMatchingFilterChainResolver;
import com.nercel.dsj.gksales.shiro.filter.*;
import com.nercel.dsj.gksales.shiro.service.ShiroService;
import com.nercel.dsj.gksales.shiro.util.ShiroUtil;
import com.nercel.dsj.gksales.util.SpringUtil;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author sunlin
 * @date 2018-11-20
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ShiroServiceImpl implements ShiroService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroServiceImpl.class);

	private final PermissionService permissionService;

    private final UserMapper userMapper;

    @Override
    public User getUserById(Integer id) {
        return userMapper.selectByPrimaryKey(id);
    }

    @Override
    public Map<String, String> getFilterChainMap() {
        Map<String, String> filterMap = new LinkedHashMap<>();
        QueryParams queryParams = new QueryParams();
        queryParams.put("weight", true);
        List<Permission> permissions = permissionService.list(queryParams);
        for (Permission permission : permissions) {
            if (permission.getUrl() != null && permission.getPermission() != null) {
                if (permission.getAssignable()) {
                    filterMap.put(permission.getUrl(), "jwt,restPerms[" + permission.getPermission() + "]");
//                    filterMap.put(permission.getUrl(), "jwt");
                } else {
                    if (ShiroUtil.checkPermssionsConfig(permission.getPermission())) {
                        filterMap.put(permission.getUrl(), permission.getPermission());
                    }
                }
            }else{
                //TODO exceiption handler
                LOGGER.error("Invalid permissions.");
            }
        }
        return filterMap;
    }

    @Override
    public void reloadFilterChain() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = SpringUtil.getBean(ShiroFilterFactoryBean.class);
        AbstractShiroFilter abstractShiroFilter;
        try {
            abstractShiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
			assert abstractShiroFilter != null;
			RestPathMatchingFilterChainResolver filterChainResolver
					= (RestPathMatchingFilterChainResolver) abstractShiroFilter.getFilterChainResolver();
            DefaultFilterChainManager filterChainManager
					= (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
            filterChainManager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(getFilterChainMap());
            shiroFilterFactoryBean.getFilterChainDefinitionMap().forEach(filterChainManager::createChain);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    private final JwtAuthenticationFilter jwtFilter;

    @Override
    public Map<String, Filter> getCustomFilters() {
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("restUser", new RestUserFilter());
        filters.put("restRoles", new RestRolesAuthorizationFilter());
        filters.put("restAuthc", new RestFormAuthenticationFilter());
        filters.put("restPerms", new RestPermissionsAuthorizationFilter());
        filters.put("jwt", jwtFilter);
        return filters;
    }


}
